package com.webchat.pgc.service.mall;


import com.google.common.collect.Lists;
import com.webchat.common.exception.BusinessException;
import com.webchat.common.service.RedisService;
import com.webchat.domain.dto.mall.SkuShopDTO;
import com.webchat.domain.dto.payment.PaymentResultDTO;
import com.webchat.domain.dto.queue.PaymentCallBackQueueDTO;
import com.webchat.domain.vo.request.mall.MallSKUPropertyRequestVO;
import com.webchat.domain.vo.request.mall.MallSKURequestVO;
import com.webchat.pgc.repository.dao.mall.IMallSKUDAO;
import com.webchat.pgc.repository.dao.mall.IMallSKUPropertyDAO;
import com.webchat.pgc.repository.entity.mall.MallSKU;
import com.webchat.pgc.repository.entity.mall.MallSKUProperty;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class MallSKUService {


    @Autowired
    private IMallSKUDAO mallSKUDAO;
    @Autowired
    private IMallSKUPropertyDAO mallSKUPropertyDAO;
    @Autowired
    private RedisService redisService;
    @Autowired
    @Qualifier(value = "batchQueryDBExecutor")
    private Executor batchQueryDBExecutor;


    /**
     * 保存更新sku
     *
     * @param spuId
     * @param skus
     * @param operator
     * @return
     */
    public Boolean save(Long spuId, List<MallSKURequestVO> skus, String operator) {
        // 1. 处理SKU更新
        List<Long> skuIdlist = mallSKUDAO.findBySpuId(spuId);
        if (CollectionUtils.isNotEmpty(skus)) {
            // 1.1 删除当前SPU下的sku配置
            mallSKUDAO.deleteAllById(skuIdlist);
            // 1.2 删除SKU销售属性配置
            mallSKUPropertyDAO.deleteAllBySkuIdIn(skuIdlist);
        }
        // 2. 新增SKU
        if (CollectionUtils.isEmpty(skus)) {
            return true;
        }
        List<MallSKU> skuEntityList = skus.stream().map(sku -> convert(spuId, sku)).toList();
        skuEntityList.get(0).setMainSku(true);
        skuEntityList = mallSKUDAO.saveAll(skuEntityList);
        // 3. 新增SKU销售属性配置
        List<Long> skuIdList = skuEntityList.stream().map(MallSKU::getId).toList();
        List<MallSKUProperty> skuProperties = buildMallSkuPropertyList(skuIdList, skus, operator);
        // 保存sku销售属性配置
        mallSKUPropertyDAO.saveAll(skuProperties);
        return true;
    }

    /**
     * 查询SPU下的SKU集合
     *
     * @param spuId
     * @return
     */
    public List<MallSKU> getBySpuId(Long spuId) {

        return mallSKUDAO.findAllBySpuId(spuId);
    }

    /**
     * 查询SKU数据
     *
     * @param skuId
     * @return
     */
    public MallSKU get(Long skuId) {

        return mallSKUDAO.findById(skuId).orElse(null);
    }

    /**
     * 查询SKU对应的销售属性配置
     *
     * @param skuIdList
     * @return
     */
    public List<MallSKUProperty> getPropertyBySkuIdIn(List<Long> skuIdList) {
        List<MallSKUProperty>  skuProperties = mallSKUPropertyDAO.findAllBySkuIdIn(skuIdList);
        return skuProperties;
    }


    public Map<Long, Long> batchGetSkuShopId(List<Long> skuIdList) {

        if (CollectionUtils.isEmpty(skuIdList)) {
            return Collections.emptyMap();
        }

        /**
         * 在Oracle中对in条件不能超过1000个参数有限制，主要是oracle对性能的保证
         *
         * 避免skuIdList超度过大，我们分组每组1000来查询
         */
        List<List<Long>> skuIdPartition = Lists.partition(skuIdList, 1000);
        List<CompletableFuture<List<SkuShopDTO>>> futures = new ArrayList<>();
        List<SkuShopDTO> queryDbResult = new ArrayList<>();
        /**
         * 基于自定义线程池paymentCallBackExecutor，并行出执行批量回调任务
         *
         */
        for (List<Long> skuIds : skuIdPartition) {
            CompletableFuture<List<SkuShopDTO>> future =
                    CompletableFuture.supplyAsync(() -> mallSKUDAO.querySkuShopId(skuIds), batchQueryDBExecutor);
            futures.add(future);
        }
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        for (int i = 0; i < futures.size(); i++) {
            try {
                List<SkuShopDTO> skuShopDTOList = futures.get(i).get();
                if (CollectionUtils.isEmpty(skuShopDTOList)) {
                    continue;
                }
                queryDbResult.addAll(skuShopDTOList);
            } catch (Exception e) {
                // TODO
                throw new BusinessException("店铺信息查询失败");
            }
        }
        if (CollectionUtils.isEmpty(queryDbResult)) {
            return Collections.emptyMap();
        }
        return queryDbResult.stream().collect(Collectors.toMap(SkuShopDTO::getSkuId, SkuShopDTO::getShopId));
    }

    private List<MallSKUProperty> buildMallSkuPropertyList(List<Long> skuIdList,
                                                           List<MallSKURequestVO> skus,
                                                           String operator) {
        Date now = new Date();
        List<MallSKUProperty> skuProperties = new ArrayList<>();
        for (int i = 0; i < skus.size(); i++) {
            List<MallSKUPropertyRequestVO> properties = skus.get(i).getProperties();
            Long skuId = skuIdList.get(i);
            for (MallSKUPropertyRequestVO property : properties) {
                MallSKUProperty skuProperty = new MallSKUProperty();
                skuProperty.setSkuId(skuId);
                skuProperty.setPropertyNameId(property.getPropertyNameId());
                skuProperty.setPropertyValueId(property.getPropertyValueId());
                skuProperty.setCreateBy(operator);
                skuProperty.setCreateDate(now);
                skuProperties.add(skuProperty);
            }
        }
        return skuProperties;
    }

    private MallSKU convert(Long spuId, MallSKURequestVO sku) {
        MallSKU skuEntity = new MallSKU();
        skuEntity.setSpuId(spuId);
        skuEntity.setMainSku(false);
        skuEntity.setPrice(sku.getPrice());
        skuEntity.setOriginPrice(sku.getOriginPrice());
        skuEntity.setPublish(sku.getPublish());
        skuEntity.setStock(sku.getStock());
        skuEntity.setImage(sku.getImage());
        return skuEntity;
    }
}
